#include "Renderer.h"
#include <sstream>

#define GL_CHECK(x) {\
(x);\
GLenum error = glGetError();\
if (GL_NO_ERROR != error) {\
printf("%s", gluErrorString(error));\
}\
}

Renderer::Renderer(Camera *camera_, AIEngine* aiEngine_) {
	modelPaths.push_back("Scene/square_hedge_maze.3ds");
	modelPaths.push_back("Scene/character_idle.dae");
	modelPaths.push_back("Scene/character_running.dae");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");
	modelPaths.push_back("Scene/enemy2.3ds");

	float enemyPositions[63] = {30.0, 9.0, 302.0,
				  60.0, 9.0, 302.0,
				-118.460580, 9.0, 188.164056,
				-210.475143, 9.0, 108.766475,
				-210.691580, 9.0, -47.118169,
				-351.426338, 9.0, -69.502615,
				-163.517203, 9.0, -309.952778,
				56.356882, 9.0, -303.802578,
				144.879295, 9.0, -349.285684,
				254.736053, 9.0, -221.472830,
				257.815379, 9.0, -48.133832,
				239.592533, 9.0, 213.167920,
				-71.363119, 9.0, 57.103844,
				68.075595, 9.0, -59.410656,
				68.781357, 9.0, -202.753605,
				166.354633, 9.0, -160.500669,
				396.739799, 9.0, -86.859194,
				220.706735, 9.0, 24.689522,
				6.451983, 9.0, 24.953013,
				-136.633791, 9.0, -116.208581,
				-48.009152, 9.0, -163.939245 };

	camera = camera_;
	drawShadows = false;
	bias[0] = 0.5; bias[1] = 0; bias[2] = 0; bias[3] = 0;
	bias[4] = 0; bias[5] = 0.5; bias[6] = 0; bias[7] = 0;
	bias[8] = 0; bias[9] = 0; bias[10] = 0.5; bias[11] = 0;
	bias[12] = 0.5; bias[13] = 0.5; bias[14] = 0.5; bias[15] = 1.0;
	aiEngine = aiEngine_;	
	loadAssets();
	int posIndex = 0;
	for (unsigned int i = 3; i < modelPaths.size() - 21; i++) {
		aiEngine->addEnemy(enemyPositions[posIndex], enemyPositions[posIndex + 1],
			enemyPositions[posIndex + 2], 0.2);
		posIndex += 3;	
	}
	displayCharacterIdleRenderer = new DisplayCharacter();
	displayCharacterRunningRenderer = new DisplayCharacter();
	resultPos = new std::vector<aiVector3D>();
}

void Renderer::loadTextureData(const aiScene *scene) {
	for (unsigned int i=0; i < scene->mNumMeshes; i++) {
		aiMesh* mesh = scene->mMeshes[i];
		aiString path;
		scene->mMaterials[mesh->mMaterialIndex]->GetTexture(aiTextureType_DIFFUSE, 0, &path);
		aiString fullPath;
		printf("path is %s\n", path.data);
		fullPath.Append("Scene/");
		fullPath.Append(path.data);
		fullPath.Append("_d.jpg");
		sf::Image *image = new sf::Image();
		bool result = image->LoadFromFile(fullPath.data);
		if (result) {
			std::string key = std::string(fullPath.data);
			if (textures.find(key) == textures.end()) {
				image->Bind();
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
				glGenerateMipmapEXT(GL_TEXTURE_2D);
				textures[key] = image;
			} else {
				delete(image);
			}
		} else { 
			image->Create(1,1,sf::Color(255,255,255,255));
			std::string key = std::string(fullPath.data);
			textures[key] = image;
		}

		fullPath.Clear();
		fullPath.Append("Scene/");
		fullPath.Append(path.data);
		fullPath.Append("_s.jpg");
		image = new sf::Image();
		result = image->LoadFromFile(fullPath.data);
		if (result) {
			std::string key = std::string(fullPath.data);
			if (textures.find(key) == textures.end()) {
			        printf("find image for %s\n", key.c_str());
				image->Bind();
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
				glGenerateMipmapEXT(GL_TEXTURE_2D);
				textures[key] = image;
			} else {
				delete(image);
			}
		} else { 
		        image->Create(1,1,sf::Color(255,255,255,255));
			std::string key = std::string(fullPath.data);
                        printf("generate a white image for %s\n", key.c_str());
			textures[key] = image;
		}

		fullPath.Clear();
		fullPath.Append("Scene/");
		fullPath.Append(path.data);
		fullPath.Append("_n.jpg");
		image = new sf::Image();
		result = image->LoadFromFile(fullPath.data);
		if (result) {
			std::string key = std::string(fullPath.data);
			if (textures.find(key) == textures.end()) {
				image->Bind();
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
				glGenerateMipmapEXT(GL_TEXTURE_2D);
				textures[key] = image;
			} else {
				delete(image);
			}
		} else { //Create All blue image for normal mapping if it doesnt exist
			image->Create(1,1,sf::Color(128,128,255,255));	//128 128 255 because they'll get converted from 0-1 to -1 to 1
			std::string key = std::string(fullPath.data);
			textures[key] = image;
		}
	}
}

void Renderer::loadParticleTextures() {

	fireTexture = new sf::Image();
	if (fireTexture->LoadFromFile("particles/FireGold.png")){
		 printf("Success load of particles/FireGold.png\n");//bleh
	} 

        sparkTexture = new sf::Image();
        if (sparkTexture->LoadFromFile("particles/SparkBlue.png")){
	  printf("Success load of particles/SparkBlue.png\n");//bleh
	}

 }

void Renderer::loadAssets() {
	for (unsigned int i=0; i < modelPaths.size() - aiEngine->getNumEnemies(); i++) {
		const aiScene *scene;
		Assimp::Importer *importer = new Assimp::Importer();
		scene = importer->ReadFile(modelPaths[i],  
			aiProcess_CalcTangentSpace |
			aiProcess_Triangulate |
			aiProcess_JoinIdenticalVertices |
			aiProcess_FlipUVs |
			aiProcess_TransformUVCoords |
			aiProcessPreset_TargetRealtime_Quality);

		if (!scene || scene->mNumMeshes <= 0) {
			std::cerr << importer->GetErrorString() << std::endl;
			exit(-1);
		}
		loadTextureData(scene);
		scenes.push_back(scene);
		importers.push_back(importer);
	}

	font = new sf::Font();
	if (!font->LoadFromFile("fonts/arial.ttf", 50)) {
		printf("Could not load font file\n");	
	}
	// You can also use the constructor
	statusString = new sf::String("initializing text...", sf::Font::GetDefaultFont(), 30.f);
	statusString->SetColor(sf::Color(255, 255, 255));
	statusString->SetPosition(20.f, 20.f);	

	loadParticleTextures();

	//Load shade image
	sf::Image *image = new sf::Image();
	bool result = image->LoadFromFile("Scene/celshade.tga");
	if (result) {
		std::string key = std::string("celShade");
		image->Bind();
		textures[key] = image;
	}

	
	//Phong shader
	phong = new Shader("shaders/phong");
	if (!phong->loaded()) {
		std::cerr << "Phong failed to load" << std::endl;
		std::cerr << phong->errors() << std::endl;
		exit(-1);
	}	
	//Normal color shader
	normalCol = new Shader("shaders/normalcol");
	if (!normalCol->loaded()) {
		std::cerr << "Normal color failed to load" << std::endl;
		std::cerr << normalCol->errors() << std::endl;
		exit(-1);
	}	
	//Phong Toon shader
	phongToon = new Shader("shaders/phongToon");
	if (!phongToon->loaded()) {
		std::cerr << "Phong Toon failed to load" << std::endl;
		std::cerr << phongToon->errors() << std::endl;
		exit(-1);
	}

	textureDraw = new Shader("shaders/textureDraw");
	if (!textureDraw->loaded()) {
		std::cerr << "Texture Draw failed to load" << std::endl;
		std::cerr << textureDraw->errors() << std::endl;
		exit(-1);
	}

	shadow = new Shader("shaders/shadow");
	if (!shadow->loaded()) {
		std::cerr << "Shadow failed to load" << std::endl;
		std::cerr << shadow->errors() << std::endl;
		exit(-1);
	}

	// Outline Shader
        outline = new Shader("shaders/outline");
	if (!outline->loaded()) {
		std::cerr << "outline failed to load" << std::endl;
		std::cerr << outline->errors() << std::endl;
		exit(-1);
	}

        // Outline Filter Shader
        outlineFilter = new Shader("shaders/outlineFilter");
	if (!outlineFilter->loaded()) {
		std::cerr << "outline Filter failed to load" << std::endl;
		std::cerr << outlineFilter->errors() << std::endl;
		exit(-1);
	}

	// OutlinePlusScene Shader
        outlinePlusScene = new Shader("shaders/outlinePlusScene");
	if (!outlinePlusScene->loaded()) {
		std::cerr << "outline Plus Scene failed to load" << std::endl;
		std::cerr << outlinePlusScene->errors() << std::endl;
		exit(-1);
	}


	// Thickness Shader
        thickness = new Shader("shaders/thickness");
	if (!thickness->loaded()) {
		std::cerr << "thickness failed to load" << std::endl;
		std::cerr << thickness->errors() << std::endl;
		exit(-1);
	}

	//Phong Toon Shadow shader
	phongToonShadow = new Shader("shaders/phongToonShadow");
	if (!phongToonShadow->loaded()) {
		std::cerr << "Phong Toon Shadow failed to load" << std::endl;
		std::cerr << phongToonShadow->errors() << std::endl;
		exit(-1);
	}

	//particle shader
	particle = new Shader("shaders/particle");
	if (!particle->loaded()) {
		std::cerr << "particle failed to load" << std::endl;
		std::cerr << particle->errors() << std::endl;
		exit(-1);
	}

}

void Renderer::setLightTextureMatrix() {
	glGetDoublev(GL_MODELVIEW_MATRIX, lightModelView);
	glGetDoublev(GL_PROJECTION_MATRIX, lightProjection);

	glMatrixMode(GL_TEXTURE);
	glActiveTexture(GL_TEXTURE7);
	
	glLoadIdentity();	
	glLoadMatrixd(bias);
	
	glMultMatrixd(lightProjection);
	glMultMatrixd(lightModelView);
	
	glMatrixMode(GL_MODELVIEW);
}

void Renderer::setMaterial(aiMesh *mesh, const aiScene *scene) {
    aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
    aiColor3D color;

    // Get a handle to the diffuse, specular, and ambient variables
    // inside the shader. Then set them with the diffuse, specular, and
    // ambient color.
    GLint diffuse = glGetUniformLocation(currentShader->programID(), "Kd");
    material->Get(AI_MATKEY_COLOR_DIFFUSE, color);
    glUniform3f(diffuse, color.r, color.g, color.b);

    // Specular material
    GLint specular = glGetUniformLocation(currentShader->programID(), "Ks");
    material->Get(AI_MATKEY_COLOR_DIFFUSE, color);
    glUniform3f(specular, color.r, color.g, color.b);
  
    // Ambient material
    GLint ambient = glGetUniformLocation(currentShader->programID(), "Ka");
    material->Get(AI_MATKEY_COLOR_DIFFUSE, color);
    glUniform3f(ambient, color.r, color.g, color.b);

    // Specular power
    GLint shininess = glGetUniformLocation(currentShader->programID(), "alpha");
    float value;
    if (AI_SUCCESS == material->Get(AI_MATKEY_SHININESS, value)) {
        glUniform1f(shininess, value);
    } else {
        glUniform1f(shininess, 32);
    }
}

void Renderer::setTextures(aiMesh *mesh, const aiScene *scene) {

	aiString path;
	scene->mMaterials[mesh->mMaterialIndex]->GetTexture(aiTextureType_DIFFUSE, 0, &path);
	aiString fullPath;

        
	fullPath.Append("Scene/");
	fullPath.Append(path.data);
	fullPath.Append("_d.jpg");
	std::string key = std::string(fullPath.data);
        
	sf::Image *imageDiffuse = textures[key];
	GLint diffuse = glGetUniformLocation(currentShader->programID(), "diffuseMap");
        glUniform1i(diffuse, 0); // The diffuse map will be GL_TEXTURE0
        glActiveTexture(GL_TEXTURE0); // ACTIVATE GL_TEXTURE0
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	imageDiffuse->Bind();
	
	if (currentShader == phongToon) {
		sf::Image *imageShade = textures["celShade"];
		GLint shadeMap = glGetUniformLocation(currentShader->programID(), "celShadeMap");
	        glUniform1i(shadeMap, 1);
	        glActiveTexture(GL_TEXTURE1);
		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		imageShade->Bind();			
	}

        // LET'S NOT WORRY ABOUT SPECULAR TEXTURE FOR NOW

/*        
	fullPath.Clear();
	fullPath.Append("Scene/");
	fullPath.Append(path.data);
	fullPath.Append("_s.jpg");
	key = std::string(fullPath.data);
	sf::Image *imageSpecular = textures[key];     
        

	// OKAY it's official that SOMETHING IN SETTING THE SPECULARMAP
        // MESS UP
	// Transparency
	GLint specular = glGetUniformLocation(currentShader->programID(),"specularMap");
	GL_CHECK(glUniform1i(specular, 1)); // The transparency map will be GL_TEXTURE1
	GL_CHECK(glActiveTexture(GL_TEXTURE1));
	GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
	GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
	imageSpecular->Bind();
        */
        

/*
	fullPath.Append("Scene/");
	fullPath.Append(path.data);
	fullPath.Append("_n.jpg");
	key = std::string(fullPath.data);
	sf::Image *imageNormal = textures[key];
	GLint normal = glGetUniformLocation(currentShader->programID(), "normalMap");
	glUniform1i(normal, 2); // The normal map will be GL_TEXTURE2
	glActiveTexture(GL_TEXTURE2);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	imageNormal->Bind();
*/

}


void Renderer::disableVertexAttributeArrays() {
	GLint position = glGetAttribLocation(currentShader->programID(), "positionIn");
    	GL_CHECK(glDisableVertexAttribArray(position));

	if (currentShader == phong || currentShader == phongToon) {
	  //printf("disable texcoord attrib. array\n");
    		GLint texcoord = glGetAttribLocation(currentShader->programID(), "texcoordIn");
    		GL_CHECK(glDisableVertexAttribArray(texcoord));
	}	
	if (currentShader != shadow) {
	  //    printf("disable normal attrib. array\n");
    		GLint normal = glGetAttribLocation(currentShader->programID(), "normalIn");
    		GL_CHECK(glDisableVertexAttribArray(normal));
	}
}

void Renderer::setMeshData(aiMesh *mesh, aiMatrix4x4 *model, aiVector3D *vertices) {
	// Get a handle to the variables for the vertex data inside the shader.
	GLint position = glGetAttribLocation(currentShader->programID(), "positionIn");
	GL_CHECK(glEnableVertexAttribArray(position));
	GL_CHECK(glVertexAttribPointer(position, 3, GL_FLOAT, 0, sizeof(aiVector3D), vertices));

	if (currentShader == phong || currentShader == phongToon) {
		// Texture coords. Note the [0] at the end, very important
		GLint texcoord = glGetAttribLocation(currentShader->programID(), "texcoordIn");
		GL_CHECK(glEnableVertexAttribArray(texcoord));
		GL_CHECK(glVertexAttribPointer(texcoord, 2, GL_FLOAT, 0, sizeof(aiVector3D), mesh->mTextureCoords[0]));
	}
	if (currentShader != shadow) {
		// Normals
		GLint normal = glGetAttribLocation(currentShader->programID(), "normalIn");
		GL_CHECK(glEnableVertexAttribArray(normal));
		GL_CHECK(glVertexAttribPointer(normal, 3, GL_FLOAT, 0, sizeof(aiVector3D), mesh->mNormals));
	}
}

void Renderer::renderAllScenes()
{
	aiMatrix4x4 identity(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);

	for (unsigned int i=0; i < scenes.size() - aiEngine->getNumEnemies(); i++){
		if (i == 1 && camera->idle) {	
			glPushMatrix();
			aiEngine->placeCharacter();
			currentDisplayCharacterRenderer = displayCharacterIdleRenderer;		
			currentDisplayCharacterRenderer->OnRender(scenes.at(i));
			recursive_render(scenes.at(i), scenes.at(i)->mRootNode, identity, true);
			glPopMatrix();
		} else if (i==2 && !camera->idle) {
			glPushMatrix();
			aiEngine->placeCharacter();		
			if (camera->idle) {
				i++;
			}
			currentDisplayCharacterRenderer = displayCharacterRunningRenderer;	
			currentDisplayCharacterRenderer->OnRender(scenes.at(i));
			recursive_render(scenes.at(i), scenes.at(i)->mRootNode, identity, true);
			glPopMatrix();			
		} else if (i > 2) {
			glPushMatrix();
			aiEngine->placeEnemy(i - 3);
			int offset = 0;
			if (aiEngine->getEnemy(i - 3)->anim == 1) {
				offset += aiEngine->getNumEnemies();
			}
			recursive_render(scenes.at(i + offset), scenes.at(i + offset)->mRootNode, identity, false);
			glPopMatrix();
		} else {
			recursive_render(scenes.at(i), scenes.at(i)->mRootNode, identity, false);
		}
	}
	std::stringstream ss;
	ss << camera->getFollowersSize() << "/" << aiEngine->getNumEnemies() << " found";
	statusString->SetText(ss.str());
}

void Renderer::recursive_render(const aiScene *scene, const aiNode* nd, aiMatrix4x4 model, bool drawBones) {
	aiMatrix4x4 m = nd->mTransformation;
	aiTransposeMatrix4(&m);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glMultMatrixf((float*)&m);
	if (drawShadows) {
		glMatrixMode(GL_TEXTURE);
		glActiveTexture(GL_TEXTURE7);	
		model = model * m;
		glLoadIdentity();	
		glLoadMatrixd(bias);		
		glMultMatrixd(lightProjection);
		glMultMatrixd(lightModelView);
		glMultMatrixf((float*) &model);
	}
	for (unsigned int n=0; n < nd->mNumMeshes; n++) {
		aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
		if (mesh->mPrimitiveTypes != GL_TRIANGLES) {
			continue;
		}

                
		if (currentShader == phong || currentShader == phongToon) {
		        setTextures(mesh, scene);
			setMaterial(mesh, scene);
		}
                if (drawBones) {			
			currentDisplayCharacterRenderer->DrawBone(scene, mesh, resultPos);
			setMeshData(mesh, &m, &(resultPos->at(0)));
		} else {
			setMeshData(mesh, &m, mesh->mVertices);		
		}
		std::vector<unsigned> indexBuffer;
		indexBuffer.reserve(mesh->mNumFaces * 3);
		for (unsigned j = 0; j < mesh->mNumFaces; j++) {
			for (unsigned k = 0; k < mesh->mFaces[j].mNumIndices; k++) {
				indexBuffer.push_back(mesh->mFaces[j].mIndices[k]);
			}
		}

		int count = indexBuffer.size();
		glDrawElements(mesh->mPrimitiveTypes,  count, GL_UNSIGNED_INT, &indexBuffer[0]);
		
	}
	
	// draw all children	
	for (unsigned int n = 0; n < nd->mNumChildren; n++) {
		recursive_render(scene, nd->mChildren[n], model, drawBones);
	}

	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();

}

// pass in an array of enemies
void Renderer::renderAllParticles(float elapsedTime)
{

     unsigned int enemyNum = aiEngine->getEnemies()->size();
    
     for (unsigned i=0; i< enemyNum; i++){
        
         Enemy *enemy = aiEngine->getEnemies()->at(i);
         if (!enemy->following) continue;

	 enemy->getEmitter()->emit(elapsedTime);
	 
         // pass in the array of particles
	 unsigned pNum = enemy->getEmitter()->particles.size();
         //printf("pNum = %d\n",pNum);
	 CannonParticle* particleArr = new CannonParticle [pNum];
         for (unsigned i=0 ; i< pNum; i++){
	   particleArr[i] = enemy->getEmitter()->particles[i];
	 }

	 // particleArr: position
	 GLint position = glGetAttribLocation(currentShader->programID(),"positionIn");
	 GL_CHECK(glEnableVertexAttribArray(position));
         GL_CHECK(glVertexAttribPointer(position, 3, GL_FLOAT, 0, sizeof(CannonParticle), particleArr));
         GL_CHECK(glDrawArrays(GL_POINTS, 0, pNum));
	 GL_CHECK(glDisableVertexAttribArray(position));

	 delete [] particleArr;
         enemy->getEmitter()->updateMyParticles(elapsedTime);
     }
     // important: disable
    
}
